﻿using UnityEngine;
using Jinndev.UI;
#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem;
#endif

namespace Jinndev.GameKit {

    /// <summary>
    /// 库存工具类
    /// </summary>
    public static class InventoryUtil {

        /// <summary>
        /// 根据配置id得到最大叠加数量
        /// </summary>
        public delegate int GetMaxDelegate(int id);
        public static GetMaxDelegate GetMax { get; set; }

        /// <summary>
        /// 是否可以将物品放入指定库存
        /// </summary>
        public delegate bool CheckCanReceiveDelegate(Item item, Inventory toInventory, int toIndex);
        public static CheckCanReceiveDelegate CheckCanReceive { get; set; }

        /// <summary>
        /// 扔掉物品的方法
        /// </summary>
        public delegate void DropItemDelegate(int id, int num);
        public static DropItemDelegate DropItem { get; set; }

        /// <summary>
        /// 是否开启快速转移，如按下shift时点击物品，可快速转移至其他指定库存
        /// </summary>
        public static bool EnableQuickTransfer = false;

        /// <summary>
        /// 开始拾取
        /// </summary>
        public static System.Action OnStartPick;
        /// <summary>
        /// 结束拾取
        /// </summary>
        public static System.Action OnEndPick;
        /// <summary>
        /// 拾取物品变化
        /// </summary>
        public static System.Action OnChangePick;


        /// <summary>
        /// 当前拿起的物品
        /// </summary>
        public static IItemUI PickingItemUI = null;
        /// <summary>
        /// 拿起物品的源库存
        /// </summary>
        public static Inventory OriginInventory = null;
        /// <summary>
        /// 拿起物品的源库存索引
        /// </summary>
        public static int OriginIndex = -1;

        /// <summary>
        /// 是否正在拿着物品
        /// </summary>
        public static bool PickingItem { get { return PickingItemUI != null; } }




        /// <summary>
        /// 点击在物品UI上时
        /// </summary>
        /// <param name="inventory">点击发生的库存</param>
        /// <param name="index">点击的物品槽索引</param>
        /// <param name="itemUI">点击的物品UI</param>
        /// <param name="pickAction">拾取行为</param>
        /// <param name="dropAction">放置行为</param>
        /// <param name="checkCanReceive">检查是否可以接收的回调方法</param>
        public static void OnClickItem(Inventory inventory, int index, IItemUI itemUI, PickAction pickAction, DropAction dropAction) {
            if (PickingItem == false) {
                // 空手
                if (EnableQuickTransfer && inventory.quickTransferTarget != null) {
                    // 快速转移
                    QuickTransfer(inventory, index, itemUI, pickAction, dropAction);
                }
                else {
                    // 需要拿起物品
                    PickItem(inventory, index, itemUI, pickAction, dropAction);
                }
            }
            else {
                // 正拿着其他物品，需要决定放下行为
                PutItem(inventory, index, itemUI, pickAction, dropAction);
            }
        }

        /// <summary>
        /// 拾取物品操作
        /// </summary>
        /// <param name="inventory">点击发生的库存</param>
        /// <param name="index">点击的物品槽索引</param>
        /// <param name="itemUI">点击的物品UI</param>
        /// <param name="pickAction">拾取行为</param>
        /// <param name="dropAction">放置行为</param>
        private static void PickItem(Inventory inventory, int index, IItemUI itemUI, PickAction pickAction, DropAction dropAction) {
            // 决定拾取数量
            int pickNum = 0;
            if (pickAction == PickAction.PickAll) {
                pickNum = inventory[index].num;
            }
            else if (pickAction == PickAction.PickHalf) {
                pickNum = inventory[index].num > 1 ? inventory[index].num / 2 : inventory[index].num;
            }
            if (pickNum <= 0) {
                return;
            }

            if (inventory.Setting.pickBehaviour == PickBehaviour.Pick) {
                // 直接拿起
                CreatePickingItemUI(inventory, index, pickNum, itemUI, false);
            }
            else if (inventory.Setting.pickBehaviour == PickBehaviour.Copy) {
                // 复制全部，然后拿起
                CreatePickingItemUI(inventory, index, pickNum, itemUI, true);
            }
        }

        /// <summary>
        /// 放下物品操作
        /// </summary>
        private static void PutItem(Inventory inventory, int index, IItemUI itemUI, PickAction pickAction, DropAction dropAction) {
            if (dropAction == DropAction.CancelPick) {
                // 取消拾取状态
                CancelPickingItem();
                return;
            }
            if (dropAction == DropAction.Disable) {
                // 不支持放下
                return;
            }

            bool dropOne = dropAction == DropAction.DropOne;
            bool isSelf = inventory == OriginInventory;
            if (isSelf) {
                // 放入自身库存
                if (OriginInventory.Setting.dropIntoSelfInventory == DropIntoSelfInventory.DropCombineSwap) {
                    // 放下、合并、交换
                    DropCombineSwap(inventory, index, dropAction);
                }
            }
            else {
                // 放入其他库存
                if (OriginInventory.Setting.dropIntoOtherInventory == DropIntoOtherInventory.Cancel) {
                    // 放回
                    CancelPickingItem();
                }
                else if (OriginInventory.Setting.dropIntoOtherInventory == DropIntoOtherInventory.Destroy) {
                    // 销毁
                    DestroyPickingItemUI();
                }
                else if (OriginInventory.Setting.dropIntoOtherInventory == DropIntoOtherInventory.ByReceiver) {
                    // 由接收者决定

                    // 检查外部条件
                    bool canReceive = CheckCanReceive == null || CheckCanReceive.Invoke(PickingItemUI.Item, inventory, index);
                    if (!canReceive) {
                        return;
                    }

                    if (inventory.Setting.receiveFromOtherInventory == ReceiveFromOtherInventory.DropCombineSwap) {
                        // 放下、合并、交换
                        DropCombineSwap(inventory, index, dropAction);
                    }
                    else if (inventory.Setting.receiveFromOtherInventory == ReceiveFromOtherInventory.Override) {
                        // 覆盖，强制放入
                        if (dropOne) {
                            // 放入一个
                            Item item = PickingItemUI.Item;
                            inventory.SetItem(index, new Item(item.id, 1, item.max));

                            item.num -= 1;
                            if (item.num <= 0) {
                                DestroyPickingItemUI();
                            }
                            else {
                                PickingItemUI.Item = item;
                                OnChangePick?.Invoke();
                            }
                        }
                        else {
                            // 放入全部
                            inventory.SetItem(index, PickingItemUI.Item);
                            DestroyPickingItemUI();
                        }
                    }
                    else if (inventory.Setting.receiveFromOtherInventory == ReceiveFromOtherInventory.CopyOverride) {
                        // 复制一份覆盖放入，并尝试放回原物
                        if (dropOne) {
                            // 放入一个
                            Item item = PickingItemUI.Item;
                            inventory.SetItem(index, new Item(item.id, 1, item.max));

                            item.num -= 1;
                            if (item.num <= 0) {
                                DestroyPickingItemUI();
                            }
                            else {
                                PickingItemUI.Item = item;
                                OnChangePick?.Invoke();
                            }
                        }
                        else {
                            // 放入全部
                            inventory.SetItem(index, PickingItemUI.Item);
                            CancelPickingItem();
                        }
                    }
                    else if (inventory.Setting.receiveFromOtherInventory == ReceiveFromOtherInventory.CancelPick) {
                        // 放回原物并拿起当前格子
                        CancelPickingItem();
                        PickItem(inventory, index, itemUI, pickAction, dropAction);
                    }
                }
            }
        }

        /// <summary>
        /// 快速转移当前物品到目标库存
        /// </summary>
        /// <param name="inventory">点击发生的库存</param>
        /// <param name="index">点击的物品槽索引</param>
        /// <param name="itemUI">点击的物品UI</param>
        /// <param name="pickAction">拾取行为</param>
        /// <param name="dropAction">放置行为</param>
        /// <param name="checkCanReceive">检查是否可以接收的回调方法</param>
        private static void QuickTransfer(Inventory inventory, int index, IItemUI itemUI, PickAction pickAction, DropAction dropAction) {
            // 当前是否空槽
            Item item = inventory[index];
            if (item.IsEmptyID()) {
                return;
            }
            // 目标库存是否可以存放
            if (dropAction == DropAction.CancelPick || dropAction == DropAction.Disable) {
                // 取消拾取状态 || 不支持放下
                return;
            }
            // 当前库存的策略
            if (inventory.Setting.dropIntoOtherInventory == DropIntoOtherInventory.Cancel
                || inventory.Setting.dropIntoOtherInventory == DropIntoOtherInventory.Destroy) {
                // 放回 || 销毁
                return;
            }
            else if (inventory.Setting.dropIntoOtherInventory == DropIntoOtherInventory.ByReceiver) {
                // 由接收者决定
                Inventory targetInventory = inventory.quickTransferTarget;

                // 检查外部条件
                bool canReceive = CheckCanReceive == null || CheckCanReceive.Invoke(item, targetInventory, index);
                if (!canReceive) {
                    return;
                }

                bool isCopy = inventory.Setting.pickBehaviour == PickBehaviour.Copy || targetInventory.Setting.receiveFromOtherInventory == ReceiveFromOtherInventory.CopyOverride;

                if (targetInventory.Setting.receiveFromOtherInventory == ReceiveFromOtherInventory.DropCombineSwap
                    || targetInventory.Setting.receiveFromOtherInventory == ReceiveFromOtherInventory.Override
                    || targetInventory.Setting.receiveFromOtherInventory == ReceiveFromOtherInventory.CopyOverride) {
                    // 放下、合并、交换 || 覆盖，强制放入 || 复制一份覆盖放入，并尝试放回原物
                    // 此情况可以合并或放入空格
                    int leftNum = targetInventory.Add(item.id, item.num, item.max);

                    if (leftNum != item.num) {
                        // 如果不是复制的，则要修改原库存
                        if (!isCopy) {
                            inventory.SetNum(index, leftNum);
                        }
                        targetInventory.onQuickTransferred?.Invoke();
                    }
                    return;
                }
                else if (targetInventory.Setting.receiveFromOtherInventory == ReceiveFromOtherInventory.CancelPick) {
                    // 放回原物并拿起当前格子
                    return;
                }
            }
        }

        ///// <summary>
        ///// 尝试把item放入inventory
        ///// </summary>
        ///// <param name="item"></param>
        ///// <param name="inventory"></param>
        //private static void QuickTransferItem(Item item, Inventory inventory) {
        //    int left = inventory.Add(item.id, item.num, item.max);
        //}

        /// <summary>
        /// 尝试将物品扔到背景界面
        /// </summary>
        public static void DropOnBackground() {
            if (PickingItem) {
                if (OriginInventory.Setting.dropOnBackground == GameKit.DropOnBackground.Destroy) {
                    // 销毁
                    DestroyPickingItemUI();
                }
                else if (OriginInventory.Setting.dropOnBackground == GameKit.DropOnBackground.Drop) {
                    // 扔掉
                    if (DropItem != null) {
                        Item item = PickingItemUI.Item;
                        DropItem.Invoke(item.id, item.num);
                    }
                    DestroyPickingItemUI();
                }
                else if (OriginInventory.Setting.dropOnBackground == GameKit.DropOnBackground.PutBack) {
                    // 放回
                    CancelPickingItem();
                }
            }
        }

#if ENABLE_INPUT_SYSTEM
        public static void CancelPickingItem(InputAction.CallbackContext context) {
            CancelPickingItem();
        }
#endif

        /// <summary>
        /// 取消拿起物品状态，根据原库存设置，决定取消行为
        /// </summary>
        public static void CancelPickingItem() {
            if (PickingItem) {
                //if(OriginInventory.Setting.pickBehaviour == PickBehaviour.Copy) {
                //    // 如果是复制的，不用放回，直接销毁
                //}
                //else {

                //}
                // 放回
                Item item = PickingItemUI.Item;
                int leftNum = OriginInventory.AddTo(OriginIndex, item.id, item.num, item.max);
                if (leftNum > 0) {
                    // 没放完，尝试放入其他格子
                    leftNum = OriginInventory.Add(item.id, leftNum, item.max);
                }
                if (leftNum > 0) {
                    // 没放完，扔掉
                    // TODO
                    Debug.LogError("NotImplemented");
                }
            }
            // 销毁UI
            DestroyPickingItemUI();
        }

        private static void DropCombineSwap(Inventory inventory, int index, DropAction dropAction) {
            Item targetItem = inventory[index];
            Item pickItem = PickingItemUI.Item;

            int dropNum = 0;
            if (dropAction == DropAction.DropAll) {
                dropNum = pickItem.num;
            }
            else if (dropAction == DropAction.DropOne) {
                dropNum = 1;
            }

            if (targetItem.IsEmptyID()) {
                // 空白格子，放下n个
                AddItem(inventory, index, dropNum);
            }
            else if (targetItem.id == pickItem.id) {
                // 相同物品，合并n个
                AddItem(inventory, index, dropNum);
            }
            else {
                // 不同物品，交换全部
                SwapAll(inventory, index);
            }
        }

        /// <summary>
        /// 交换手中与指定物品栏的全部物品
        /// </summary>
        private static bool SwapAll(Inventory inventory, int index) {
            Item item = PickingItemUI.Item;
            if (inventory.Replace(index, item, out Item newItem)) {
                PickingItemUI.Item = newItem;

                if (PickingItemUI.Item.IsEmptyID()) {
                    // 如果是和空格子交换，则完成后变为空手
                    DestroyPickingItemUI();
                }
                else {
                    OnChangePick?.Invoke();
                }
                return true;
            }
            return false;
        }

        /// <summary>
        /// 放入目标库存n个物品，返回剩下多少个没有放完
        /// </summary>
        private static int AddItem(Inventory inventory, int index, int num) {
            Item item = PickingItemUI.Item;
            // 放入目标库存
            int leftNum = inventory.AddTo(index, item.id, num, item.max);
            // 更新手持物品
            if (leftNum != num) {
                item.Add(leftNum - num);
                PickingItemUI.Item = item;
                OnChangePick?.Invoke();
            }
            if (item.num == 0) {
                DestroyPickingItemUI();
            }
            return leftNum;
        }

        /// <summary>
        /// 创建跟随指针的拿起的物品图标
        /// </summary>
        /// <param name="inventory">目标物品库存</param>
        /// <param name="index">目标物品库存索引</param>
        /// <param name="itemUI">目标物品图标</param>
        private static void CreatePickingItemUI(Inventory inventory, int index, int num, IItemUI itemUI, bool isCopy) {
            if (PickingItem) {
                Debug.LogError("Invalid operation");
                return;
            }
            Item item = inventory[index];
            if (num <= 0 || !item.HasItem()) {
                return;
            }

            // 如果是复制一个物品，则不应该影响原库存，所以复制一个容量为1的新库存
            if (isCopy) {
                InventorySetting copySetting = inventory.Setting;
                copySetting.onChangedKey = null;
                inventory = new Inventory(copySetting, new Item[1]);
                index = 0;
            }

            // 记录原库存
            OriginInventory = inventory;
            OriginIndex = index;

            // 分离出num数量的物品
            int splitNum = Mathf.Min(num, item.num);
            Item splitItem = new Item(item.id, splitNum, item.max);
            item.num -= splitNum;
            if (item.num == 0) {
                item = Item.Empty;
            }
            inventory.SetItem(index, item);

            // 创建物品图标
            ItemIconSetting setting = itemUI.Setting;
            setting.showIndex = false;
            setting.showBg = false;

            ItemIcon itemIcon = UIManager.Instance.AddTop<ItemIcon>(ItemIcon.PATH);
            itemIcon.Init(setting);
            itemIcon.Set(splitItem, index);
            itemIcon.EnableFloatingStyle();

            Vector2 size = (itemUI.transform as RectTransform).sizeDelta;
            FollowPointerUI followPointerUI = itemIcon.gameObject.AddComponent<FollowPointerUI>();
            followPointerUI.Init(size, size * 0.5f);

            PickingItemUI = itemIcon;

            OnStartPick?.Invoke();
        }



        /// <summary>
        /// 销毁拿着的物品UI
        /// </summary>
        private static void DestroyPickingItemUI() {
            if (PickingItemUI != null && PickingItemUI.gameObject != null) {
                Object.Destroy(PickingItemUI.gameObject);
                try {
                    OnEndPick?.Invoke();
                }
                catch (System.Exception e) {
                    Debug.LogException(e);
                }
            }
            PickingItemUI = null;
            OriginInventory = null;
            OriginIndex = -1;
        }

        /// <summary>
        /// 根据配置id得到最大叠加数量
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public static int GetMaxNum(int id) {
            if (GetMax != null) {
                return GetMax.Invoke(id);
            }
            else {
                Debug.LogError("InventoryUtil.GetMax not set");
            }
            return 0;
        }

    }

}
